<template>
  <svg :height="size" :style="{ all: 'revert' }" :width="size">
    <title>QR Code</title>
    <defs>
      <clipPath id="clip-wrapper">
        <rect :height="logoWrapperSize" :width="logoWrapperSize" />
      </clipPath>
      <clipPath id="clip-logo">
        <rect :height="logoSize" :width="logoSize" />
      </clipPath>
    </defs>
    <rect fill="transparent" :height="size" :width="size" />
    <QrcodePath :uri="uri" />
  </svg>
</template>

<script lang="ts" setup>
import QRCodeUtil, { type QRCodeErrorCorrectionLevel } from 'qrcode'
import { defineComponent, h, ref, VNode, watch } from 'vue'

const props = withDefaults(
  defineProps<{
    ecl?: QRCodeErrorCorrectionLevel
    logoMargin?: number
    logoSize?: number
    size?: number
    uri: string
  }>(),
  {
    ecl: 'M' as QRCodeErrorCorrectionLevel,
    logoMargin: 10,
    logoSize: 72,
    size: 350,
  },
)

const logoWrapperSize = props.logoSize + props.logoMargin * 2

const generateMatrix = (
  value: string,
  errorCorrectionLevel: QRCodeUtil.QRCodeErrorCorrectionLevel,
) => {
  const arr = Array.prototype.slice.call(
    QRCodeUtil.create(value, { errorCorrectionLevel }).modules.data,
    0,
  )
  const sqrt = Math.sqrt(arr.length)
  return arr.reduce(
    (rows, key, index) =>
      (index % sqrt === 0
        ? rows.push([key])
        : rows[rows.length - 1].push(key)) && rows,
    [],
  )
}

const QrcodePath = defineComponent({
  props: {
    uri: {
      type: String,
      default: '',
    },
  },
  setup(DotsProps) {
    const dots = ref<any>([])
    watch(
      () => DotsProps.uri,
      uri => {
        if (!uri) return

        const matrix = generateMatrix(uri, props.ecl)
        const cellSize = props.size / matrix.length
        const newDots: VNode[] = [] // 临时存储新生成的 dots

        // 1. 生成三个定位角（左上、右上、左下）
        const qrList = [
          { x: 0, y: 0 },
          { x: 1, y: 0 },
          { x: 0, y: 1 },
        ]

        qrList.forEach(({ x, y }) => {
          const x1 = (matrix.length - 7) * cellSize * x
          const y1 = (matrix.length - 7) * cellSize * y
          for (let i = 0; i < 3; i++) {
            newDots.push(
              h('rect', {
                fill: i % 2 !== 0 ? 'white' : 'black',
                height: cellSize * (7 - i * 2),
                key: `corner-${i}-${x}-${y}`,
                rx: (i - 2) * -5 + (i === 0 ? 2 : 0),
                ry: (i - 2) * -5 + (i === 0 ? 2 : 0),
                width: cellSize * (7 - i * 2),
                x: x1 + cellSize * i,
                y: y1 + cellSize * i,
              }),
            )
          }
        })

        // 2. 生成中间的 Logo 空白区域
        const clearArenaSize = Math.floor((props.logoSize + 25) / cellSize)
        const matrixMiddleStart = matrix.length / 2 - clearArenaSize / 2
        const matrixMiddleEnd = matrix.length / 2 + clearArenaSize / 2 - 1

        // 3. 生成数据点
        matrix.forEach((row: any, i: number) => {
          row.forEach((cell: any, j: never) => {
            if (cell) {
              // 跳过定位角和 Logo 区域
              if (
                !(
                  (
                    (i < 7 && j < 7) || // 左上角
                    (i > matrix.length - 8 && j < 7) || // 左下角
                    (i < 7 && j > matrix.length - 8)
                  ) // 右上角
                ) &&
                !(
                  i > matrixMiddleStart &&
                  i < matrixMiddleEnd &&
                  j > matrixMiddleStart &&
                  j < matrixMiddleEnd
                )
              ) {
                newDots.push(
                  h('circle', {
                    cx: j * cellSize + cellSize / 2, // 注意：i 和 j 可能反了
                    cy: i * cellSize + cellSize / 2,
                    fill: 'black',
                    key: `dot-${i}-${j}`,
                    r: cellSize / 3,
                  }),
                )
              }
            }
          })
        })

        dots.value = newDots // 一次性更新 dots
      },
      { immediate: true },
    )
    return () => dots.value
  },
})
</script>
